﻿/*
 * @author: wizardc
 */

using System.Collections.Generic;
using UnityEngine;

namespace Dou.Clock
{
    /// <summary>
    /// 时钟管理器实现
    /// </summary>
    public class ClockManagerImpl : IClockManager
    {
        private ClockTimeType _timeType;

        private bool _initialized = false;

        private bool _paused = false;
        private float _runningRate = 1;

        private float _lastTime = 0;

        private List<IClockClient> _clientList;

        public ClockManagerImpl(ClockTimeType timeType)
        {
            _timeType = timeType;
        }

        public bool paused
        {
            set
            {
                _paused = value;
            }
            get
            {
                return _paused;
            }
        }

        public float runningRate
        {
            set
            {
                _runningRate = value;
            }
            get
            {
                return _runningRate;
            }
        }

        public float time
        {
            get
            {
                return _lastTime;
            }
        }

        public void AddClient(IClockClient client)
        {
            if (!_initialized)
            {
                _initialized = true;
                initialize();
            }
            if (!_clientList.Contains(client))
            {
                _clientList.Add(client);
            }
        }

        private void initialize()
        {
            _lastTime = getTime();
            _clientList = new List<IClockClient>();
            AbstractGameMain.updateEvent += Update;
        }

        private float getTime()
        {
            switch (_timeType)
            {
                case ClockTimeType.RealTime:
                    return Time.realtimeSinceStartup;
                case ClockTimeType.UnscaledTime:
                    return Time.unscaledTime;
            }
            return Time.time;
        }

        private void Update()
        {
            if (_paused)
            {
                return;
            }
            float now = getTime();
            float passedTime = now - _lastTime;
            _lastTime = now;
            if (_clientList.Count == 0)
            {
                return;
            }
            passedTime *= _runningRate;
            int currentIndex = 0;
            int i = 0;
            for (; i < _clientList.Count; i++)
            {
                IClockClient client = _clientList[i];
                if (client != null)
                {
                    if (currentIndex != i)
                    {
                        _clientList[currentIndex] = client;
                        _clientList[i] = null;
                    }
                    currentIndex++;
                    client.Update(passedTime);
                }
            }
            if (currentIndex != i)
            {
                while (i < _clientList.Count)
                {
                    _clientList[currentIndex++] = _clientList[i++];
                }
                _clientList.RemoveRange(currentIndex, _clientList.Count - currentIndex);
            }
        }

        public bool HasClient(IClockClient client)
        {
            return _clientList.Contains(client);
        }

        public void RemoveClient(IClockClient client)
        {
            _clientList.Remove(client);
        }

        public void Clear(bool destroy = false)
        {
            _clientList.Clear();
            if (destroy)
            {
                AbstractGameMain.updateEvent -= Update;
            }
        }
    }
}
